




// #include <unistd.h>
// #include <stdlib.h>
// #include <stdio.h>

// #include "curl.h"
// #include "mk_util.h"
// #include "curl_http.h"



#include "../lib/curl/include/curl.h"
//#include "mk_util.h"
#include <stdio.h>
#include "iotv30_config.h"
#include "print_log.h"  
#include "curl_http.h"
#include "uart_printf.h"


#define TRUE				1
#define FALSE				0

/*****************************************************************************/
size_t my_write_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
  	size_t written = fwrite(ptr, size, nmemb, stream);

	fflush(stream); // 确保数据写入磁盘
    fsync(fileno(stream)); // 确保数据同步到物理介质(可选)
    //printf("wr file %lu bytes\n", size*nmemb);
	
    return written;
} 



int curl_http_download_old(const char *url, const char *file_name, progress_cb p_cb)
{
	CURL *curl;
	CURLcode res = -1;
	FILE *outfile;
	char *progress_data = "***** ";

	curl = curl_easy_init();
	if(curl)
	{
		outfile = fopen(file_name, "wb");
		if(outfile != NULL) {
		   log_debug("download file:%s", file_name);
		 
		   curl_easy_setopt(curl, CURLOPT_URL, url);
		   curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
		   curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_func);
		   curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
		   curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, p_cb);
		   curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, progress_data);

		   curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
           curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
           curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

		   // 关闭证书
		   curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
		   curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);

		   res = curl_easy_perform(curl);
		   if(res) {
		   		log_err("curl download result:%d", res);
		   }
		   else {
		   		log_notice("curl download success!");
		   }
		 
		   fclose(outfile);
		}
		else {
			log_debug("open file:%s err, download fail!", file_name);
		}
		/* always cleanup */
		curl_easy_cleanup(curl);
	}
	return res;

}

/***********************************************************************/
#include <unistd.h>
#include <sys/stat.h>

// 自定义进度回调结构
typedef struct {
    progress_cb user_cb;      // 用户进度回调
    void *user_data;         // 用户数据
    time_t last_update;      // 最后更新时间
    curl_off_t last_dlnow;   // 上次下载量
} my_progress_data;

// 自定义进度回调函数
static int my_progress_callback(void *clientp, 
                              curl_off_t dltotal, 
                              curl_off_t dlnow, 
                              curl_off_t ultotal, 
                              curl_off_t ulnow)
{
    my_progress_data *progress = (my_progress_data *)clientp;

	static time_t last_call = 0;
	time_t now = time(NULL);

	if(last_call != 0 && (now - last_call) < 1) { // 约1秒间隔
	  	return 0;
	}

	last_call = now;


   ////ota_progress err_code=0,stage=1,percent=0,
	//设备主动上报OTA升级进度 C7H
//	 logout("%s() stage=%d, done:%u/%u=%u%%\n",__FUNCTION__, stage, gotten, total, per);
//	 pb_indicate_device_ota_progress(OTA_ERR_CODE_SUCCESSED, stage, per); 
	
    
    // 调用用户进度回调
    if(progress->user_cb) {
        progress->user_cb(progress->user_data, dltotal, dlnow, 0, 0); //??????

    }

    // 检测是否卡住 (30秒无进展)
    if(progress->last_dlnow > 0 && dlnow > progress->last_dlnow) {
        progress->last_update = now;
        progress->last_dlnow = dlnow;
    } else if(now - progress->last_update > 30) {
		printf("time out exit!!!!!!\n");
        return 1; // 返回非0将终止传输
    }

	
    return 0;
}

/***************************************************************************
resume_download_flag, 1：断电续传， 0：不续传
file_len： 文件长度， 0， 长度未知
                      ~0： 实际文件长度 

*********************************************************************/
int curl_http_download(const char *url, const char *file_name, progress_cb p_cb,
	int resume_download_flag, size_t file_len)
{
    CURL *curl;
    CURLcode res = CURLE_OK;
    FILE *outfile = NULL;
    int max_retries = 3;
    int retry_count = 0;
    curl_off_t resume_from = 0;
    my_progress_data progress_data = {
        .user_cb = p_cb,
        .user_data = NULL,
        .last_update = time(NULL),
        .last_dlnow = 0
    };


	for(retry_count=0; retry_count<max_retries; retry_count++) {
		// 重置状态
        curl = NULL;
        outfile = NULL;

		resume_from = 0;	
	    struct stat file_info;      // 检查文件是否存在以支持断点续传

#if 0
		if(resume_download_flag) {
		    if(stat(file_name, &file_info) == 0) 
            {

				if(file_len != file_info.st_size) 
                {
			        resume_from = (curl_off_t)file_info.st_size;
			        log_debug("Resume download from %lld bytes\n", (long long)resume_from);
		    	}else {
					printf("download from head!\n");
				}
		    }
		}
#endif

		if( resume_download_flag &&(stat(file_name, &file_info) == 0)&&(file_len != file_info.st_size)  )
        {//文件存在且长度不同,才续传-----必须优先判断文件名 再判断文件长度
            resume_from = (curl_off_t)file_info.st_size;    //3274646
            log_debug("Resume download from %lld bytes\n", (long long)resume_from);
        }else {//否则从0开始
            printf("download from head!\n");
        }

        curl = curl_easy_init();
        if(!curl) {
            log_err("Failed to initialize curl");
			res = CURLE_FAILED_INIT;
            //return -1;
            break;
        }

        // 以追加模式打开文件(支持续传)
        outfile = fopen(file_name, resume_from ? "ab" : "wb");
        if(!outfile) {
            log_err("Failed to open file: %s", file_name);
            curl_easy_cleanup(curl);
            //return -1;
            res = CURLE_WRITE_ERROR;
			break;
        }

        // 设置基本选项
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_func);
        
        // 设置超时和连接保持选项
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 300L); // 5分钟总超时
        curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1024L); // 1KB/s最低速度
        curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60L); // 低于最低速度持续60秒则超时
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);
        curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);
        
        // 设置进度回调
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
        curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, my_progress_callback);
        curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progress_data);
        
        // 设置断点续传
        if(resume_from > 0) {
            curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, resume_from);
			 // 显式设置Range头
            char range_header[64];
            snprintf(range_header, sizeof(range_header), "%lld-", (long long)resume_from);
            curl_easy_setopt(curl, CURLOPT_RANGE, range_header);
        }
        
        // 关闭证书验证(仅用于测试，生产环境应启用)
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
	        
        // 执行下载
        res = curl_easy_perform(curl);
        if(res == CURLE_OK) {
            log_notice("Download completed successfully\n");
            break;
        }

		 // 获取HTTP响应码
        long http_code = 0;
        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
		
        // 处理错误
        log_err("Download failed (attempt %d/%d): %s, httpCode:%ld", 
               retry_count + 1, max_retries, curl_easy_strerror(res), http_code);

		// 检查服务器是否支持续传
        if(resume_from > 0 && http_code != 206) {
            log_err("Server does not support resume, disabling resume for next attempt");
            resume_download_flag = 0;
			 // 先正确关闭文件
			
	        if(outfile) {
	            fflush(outfile);
	            fclose(outfile);
	            outfile = NULL;
	        }
			#if 0
            unlink(file_name); // 删除不完整文件
			#else
			break;    //  不再尝试， 退出
			#endif
        }
			   
        // 清理其他资源
	    if(outfile) {
	        fflush(outfile);
	        fclose(outfile);
	        outfile = NULL;
	    }
	    if(curl) {
	        curl_easy_cleanup(curl);
	        curl = NULL;
	    }
		
	    // 等待指数退避时间后重试
        if(retry_count < max_retries - 1) {
            int delay = (1 << retry_count) * 8; // 2, 4, 8秒
            sleep(delay);
        }
	}

	// 清理资源
	if(outfile) fclose(outfile);
	if(curl) curl_easy_cleanup(curl);

	
	char buf[128];
	sprintf(buf, "%s%s", "ls -l ", file_name);
	printf("ls file cmd:%s\n", buf);
	system(buf);
    
    return (int)res;
}










#if 0
static size_t read_callback(void *ptr, size_t size, size_t nmemb, FILE *stream) 
{
    return fread(ptr, size, nmemb, stream);
}

int curl_http_upload_simple(const char *filename, const char *url, progress_cb p_cb) 
{
    CURL *curl;
    CURLcode res;
    // 打开待上传的文件
    FILE *fp = fopen(filename, "rb");
    if (!fp) {
        printf("无法打开文件:%s\n", filename);
        return -1;
    }
    // 初始化libcurl
    curl_global_init(CURL_GLOBAL_ALL);
    // 创建CURL对象
    curl = curl_easy_init();
    if (curl) {
        // 设置上传的URL地址    :"http://example.com/upload"
        curl_easy_setopt(curl, CURLOPT_URL, url);
        // 设置读取回调函数和数据源
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
        curl_easy_setopt(curl, CURLOPT_READDATA, fp);
		curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, p_cb);
        // 启用断点续传模式
        curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, ftell(fp));
        // 执行HTTP POST请求（使用PUT方法）
        res = curl_easy_perform(curl);
        // 检查是否发生错误
        if (res != CURLE_OK) {
            fprintf(stderr, "上传失败: %s\n", curl_easy_strerror(res));
        }
        // 清理资源
        curl_easy_cleanup(curl);
    }
    // 关闭文件句柄
    fclose(fp);
    // 清理libcurl全局资源
    curl_global_cleanup();
	
    return res;
}

#else
//#include <stdio.h>
//#include <curl/curl.h>

// 读取回调函数
size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) {
    return fread(ptr, size, nmemb, (FILE *)stream);
}

int curl_http_upload_simple(const char *filename, const char *url, progress_cb p_cb) {
    CURL *curl;
    CURLcode res;

    // 打开待上传的文件
    FILE *fp = fopen(filename, "rb");
    if (!fp) {
        printf("无法打开文件:%s\n", filename);
        return -1;
    }

    // 初始化libcurl
    curl_global_init(CURL_GLOBAL_ALL);

    // 创建CURL对象
    curl = curl_easy_init();
    if (curl) {
        // 设置上传的URL地址
        curl_easy_setopt(curl, CURLOPT_URL, url);

        // 启用PUT方法
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
	    //curl_easy_setopt(curl, CURLOPT_POST, 1L); // 启用POST方法

        // 设置读取回调函数和数据源
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
        curl_easy_setopt(curl, CURLOPT_READDATA, fp);

        // 设置文件大小
        fseek(fp, 0, SEEK_END);
        long file_size = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_size);

        // 设置进度回调函数
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, p_cb);

        // 启用调试输出
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

        // 执行HTTP请求
        res = curl_easy_perform(curl);

        // 检查是否发生错误
        if (res != CURLE_OK) {
            fprintf(stderr, "上传失败: %s\n", curl_easy_strerror(res));
        }

        // 清理资源
        curl_easy_cleanup(curl);
    }

    // 关闭文件句柄
    fclose(fp);

    // 清理libcurl全局资源
    curl_global_cleanup();

    return res;
}

#endif
